namespace Creek.UI.PropertyGridEx
{
    using System;
    using System.ComponentModel;
    using System.Drawing;
    using System.Reflection;
    using System.Windows.Forms;

    public partial class PropertyGridEx : PropertyGrid
    {
        #region "Protected variables and objects"

        // CustomPropertyCollection assigned to MyBase.SelectedObject
        protected bool bAutoSizeProperties;

        protected bool bDrawFlatToolbar;

        protected bool bShowCustomProperties;

        // CustomPropertyCollectionSet assigned to MyBase.SelectedObjects
        protected bool bShowCustomPropertiesSet;

        protected CustomPropertyCollection oCustomPropertyCollection;

        protected CustomPropertyCollectionSet oCustomPropertyCollectionSet;

        // Internal PropertyGrid Controls
        protected object oDocComment;

        protected Label oDocCommentDescription;

        protected Label oDocCommentTitle;

        protected object oHotCommands;

        protected FieldInfo oPropertyGridEntries;

        protected object oPropertyGridView;

        protected ToolStrip oToolStrip;

        // Properties variables

        #endregion

        #region "Public Functions"

        public PropertyGridEx()
        {
            // This call is required by the Windows Form Designer.
            this.InitializeComponent();

            // Add any initialization after the InitializeComponent() call.
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);

            // Initialize collections
            this.oCustomPropertyCollection = new CustomPropertyCollection();
            this.oCustomPropertyCollectionSet = new CustomPropertyCollectionSet();

            // Attach internal controls
            this.oPropertyGridView = base.GetType().BaseType.InvokeMember(
                "gridView", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance, null, this, null);
            this.oHotCommands = base.GetType().BaseType.InvokeMember(
                "hotcommands", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance, null, this, null);
            this.oToolStrip =
                (ToolStrip)
                base.GetType().BaseType.InvokeMember(
                    "toolStrip",
                    BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance,
                    null,
                    this,
                    null);
            this.oDocComment = base.GetType().BaseType.InvokeMember(
                "doccomment", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance, null, this, null);

            // Attach DocComment internal fields
            if (this.oDocComment != null)
            {
                this.oDocCommentTitle =
                    (Label)
                    this.oDocComment.GetType().InvokeMember(
                        "m_labelTitle",
                        BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance,
                        null,
                        this.oDocComment,
                        null);
                this.oDocCommentDescription =
                    (Label)
                    this.oDocComment.GetType().InvokeMember(
                        "m_labelDesc",
                        BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance,
                        null,
                        this.oDocComment,
                        null);
            }

            // Attach PropertyGridView internal fields
            if (this.oPropertyGridView != null)
            {
                this.oPropertyGridEntries = this.oPropertyGridView.GetType().GetField(
                    "allGridEntries", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
            }

            // Apply Toolstrip style
            if (this.oToolStrip != null)
            {
                this.ApplyToolStripRenderMode(this.bDrawFlatToolbar);
            }
        }

        public void MoveSplitterTo(int x)
        {
            this.oPropertyGridView.GetType().InvokeMember(
                "MoveSplitterTo",
                BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
                null,
                this.oPropertyGridView,
                new object[] { x });
        }

        public override void Refresh()
        {
            if (this.bShowCustomPropertiesSet)
            {
                base.SelectedObjects = (object[])this.oCustomPropertyCollectionSet.ToArray();
            }
            base.Refresh();
            if (this.bAutoSizeProperties)
            {
                this.AutoSizeSplitter(32);
            }
        }

        public void SetComment(string title, string description)
        {
            MethodInfo method = this.oDocComment.GetType().GetMethod("SetComment");
            method.Invoke(this.oDocComment, new object[] { title, description });
            //oDocComment.SetComment(title, description);
        }

        #endregion

        #region "Protected Functions"

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            if (this.bAutoSizeProperties)
            {
                this.AutoSizeSplitter(32);
            }
        }

        protected void AutoSizeSplitter(int RightMargin)
        {
            var oItemCollection = (GridItemCollection)this.oPropertyGridEntries.GetValue(this.oPropertyGridView);
            if (oItemCollection == null)
            {
                return;
            }
            Graphics oGraphics = Graphics.FromHwnd(this.Handle);
            int CurWidth = 0;
            int MaxWidth = 0;

            foreach (GridItem oItem in oItemCollection)
            {
                if (oItem.GridItemType == GridItemType.Property)
                {
                    CurWidth = (int)oGraphics.MeasureString(oItem.Label, this.Font).Width + RightMargin;
                    if (CurWidth > MaxWidth)
                    {
                        MaxWidth = CurWidth;
                    }
                }
            }

            this.MoveSplitterTo(MaxWidth);
        }

        protected void ApplyToolStripRenderMode(bool value)
        {
            if (value)
            {
                this.oToolStrip.Renderer = new ToolStripSystemRenderer();
            }
            else
            {
                var renderer = new ToolStripProfessionalRenderer(new CustomColorScheme());
                renderer.RoundedEdges = false;
                this.oToolStrip.Renderer = renderer;
            }
        }

        #endregion

        #region "Properties"

        [Category("Behavior")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [Description("Set the collection of the CustomProperty. Set ShowCustomProperties to True to enable it.")]
        [RefreshProperties(RefreshProperties.Repaint)]
        public CustomPropertyCollection Item
        {
            get
            {
                return this.oCustomPropertyCollection;
            }
        }

        [Category("Behavior")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [Description("Set the CustomPropertyCollectionSet. Set ShowCustomPropertiesSet to True to enable it.")]
        [RefreshProperties(RefreshProperties.Repaint)]
        public CustomPropertyCollectionSet ItemSet
        {
            get
            {
                return this.oCustomPropertyCollectionSet;
            }
        }

        [Category("Behavior")]
        [DefaultValue(false)]
        [Description("Move automatically the splitter to better fit all the properties shown.")]
        public bool AutoSizeProperties
        {
            get
            {
                return this.bAutoSizeProperties;
            }
            set
            {
                this.bAutoSizeProperties = value;
                if (value)
                {
                    this.AutoSizeSplitter(32);
                }
            }
        }

        [Category("Behavior")]
        [DefaultValue(false)]
        [Description("Use the custom properties collection as SelectedObject.")]
        [RefreshProperties(RefreshProperties.All)]
        public bool ShowCustomProperties
        {
            get
            {
                return this.bShowCustomProperties;
            }
            set
            {
                if (value)
                {
                    this.bShowCustomPropertiesSet = false;
                    base.SelectedObject = this.oCustomPropertyCollection;
                }
                this.bShowCustomProperties = value;
            }
        }

        [Category("Behavior")]
        [DefaultValue(false)]
        [Description("Use the custom properties collections as SelectedObjects.")]
        [RefreshProperties(RefreshProperties.All)]
        public bool ShowCustomPropertiesSet
        {
            get
            {
                return this.bShowCustomPropertiesSet;
            }
            set
            {
                if (value)
                {
                    this.bShowCustomProperties = false;
                    base.SelectedObjects = (object[])this.oCustomPropertyCollectionSet.ToArray();
                }
                this.bShowCustomPropertiesSet = value;
            }
        }

        [Category("Appearance")]
        [DefaultValue(false)]
        [Description("Draw a flat toolbar")]
        public new bool DrawFlatToolbar
        {
            get
            {
                return this.bDrawFlatToolbar;
            }
            set
            {
                this.bDrawFlatToolbar = value;
                this.ApplyToolStripRenderMode(this.bDrawFlatToolbar);
            }
        }

        [Category("Appearance")]
        [DisplayName("Toolstrip")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [Description("Toolbar object")]
        [Browsable(true)]
        public ToolStrip ToolStrip
        {
            get
            {
                return this.oToolStrip;
            }
        }

        [Category("Appearance")]
        [DisplayName("Help")]
        [Description("DocComment object. Represent the comments area of the PropertyGrid.")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        public Control DocComment
        {
            get
            {
                return (Control)this.oDocComment;
            }
        }

        [Category("Appearance")]
        [DisplayName("HelpTitle")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [Description("Help Title Label.")]
        [Browsable(true)]
        public Label DocCommentTitle
        {
            get
            {
                return this.oDocCommentTitle;
            }
        }

        [Category("Appearance")]
        [DisplayName("HelpDescription")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [Description("Help Description Label.")]
        [Browsable(true)]
        public Label DocCommentDescription
        {
            get
            {
                return this.oDocCommentDescription;
            }
        }

        [Category("Appearance")]
        [DisplayName("HelpImageBackground")]
        [Description("Help Image Background.")]
        public Image DocCommentImage
        {
            get
            {
                return ((Control)this.oDocComment).BackgroundImage;
            }
            set
            {
                ((Control)this.oDocComment).BackgroundImage = value;
            }
        }

        #endregion
    }
}